/**
 * <p>版权所有：中企动力
 * <p>未经本公司许可，不得以任何方式复制或使用本程序任何部分
 */
package com.ce.pms.house.dao.impl;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Query;

import com.ce.pms.base.dao.impl.PmsBaseDaoImpl;
import com.ce.pms.common.annotation.AssociatedBuildingQuery;
import com.ce.pms.common.annotation.BuildingQuery;
import com.ce.pms.common.model.SysInfo;
import com.ce.pms.common.model.SysrefcodeDO;
import com.ce.pms.common.util.PmsUtilityComparator;
import com.ce.pms.common.util.StringAnalysiUtil;
import com.ce.pms.exception.BusinessException;
import com.ce.pms.house.dao.IBuildingDao;
import com.ce.pms.house.model.BuildingDomain;
import com.ce.pms.house.model.ChargePrecinctDomain;
import com.ce.pms.house.model.HouseDomain;
import com.ce.pms.house.model.HouseGrp;
import com.ce.pms.house.model.HousePlan;
import com.ce.pms.house.vo.BuildingVO;
import com.ce.util.BlankUtil;
//import com.sun.org.apache.regexp.internal.recompile;

/**
 * 功能描述: BuildingDaoImpl
 *
 * @author  付湘辉
 * Created on：  2008-6-25
 * @author  付湘辉
 * update on：  2008-6-25
 */

public class BuildingDaoImpl extends PmsBaseDaoImpl<BuildingDomain> implements IBuildingDao {

	/**
	 *
	 * 功能描述: 根据楼栋Id得到楼栋单元列表,如果指定的楼栋不分单元，返回一个不含数据的列表
	 *
	 * @author 付湘辉
	 * Created on:2008-6-25
	 *
	 * 修改原因：
	 * @param buildingId
	 * @return List 返回结果
	 */
	public List<HouseGrp> getBuildingCells(Long buildingId) {
		List<HouseGrp> list = new ArrayList<HouseGrp>();
		if (BlankUtil.isBlank(buildingId)) {
			return list;
		}

		BuildingDomain building = super.findById(buildingId);
		String hasCell = building.getHasCell();

		if (!SysrefcodeDO.CONSTANTS_DIGITAL_ONE.equals(hasCell)) {
			return list;
		}

		Set<HouseGrp> houseGrps = building.getHouseGrps();
		if (!BlankUtil.isBlank(houseGrps)) {
			for (HouseGrp grp : houseGrps) {
				list.add(grp);
			}
		}
		Collections.sort(list, PmsUtilityComparator.getComparator());

		return list;
	}

	/**
	 * 方法描述: 查询某个管理区下的楼栋
	 * @author 胡煦
	 * Create on:2008-10-21
	 * @param precinctId
	 * @return List<BuildingDomain>
	 * Edit author:
	 * Edit on:
	 * 修改原因：
	 */
	public List<BuildingDomain> getBuildingsByPrecinctId(Long precinctId){
		String hql = "select cb from ChargePrecinctDomain cp join cp.buildings cb where cp.id = ? order by cb.seqNo";
		Query query = this.createQuery(hql, precinctId);
		return query.list();
	}


	/**
	 *
	 * 功能描述: 根据楼栋Id数组得到楼栋列表
	 *
	 * @author 胡煦
	 * Created on:2008-7-9
	 *
	 * 修改原因：
	 * @param buildingIdList
	 * @return List<BuildingDomain>
	 */
	public List<BuildingDomain> getBuildings(String buildingIds) {
		List<BuildingDomain> list = this.getBuildings(buildingIds, false);

		return list;
	}

	/**
	 * 功能描述: 根据楼栋id字符串得到楼栋实体列表,filterSign 为true 则表示buildingIds是要过滤的id <br>
	 * @param buildingIds id字符串，如：1,2,3
	 * @param filterSign 过滤标志
	 * @return List<BuildingDomain>
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-7-18  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public List<BuildingDomain> getBuildings(String buildingIds,Boolean filterSign) {
		List<BuildingDomain> list = this.getBuildingsBy(buildingIds, filterSign);
		return list;
	}

	/**
	 *
	 * 功能描述: 获取楼栋住宅层楼层阿拉伯数字列表
	 *
	 * @author 付湘辉
	 * Created on:2008-6-30
	 *
	 * 修改原因：
	 * @param buildingId 楼栋id
	 * @return List<Integer> 返回结果
	 */
	public List<Integer> getHouseStoreyList(Long buildingId){
		List<Integer> list = new ArrayList<Integer>();
		if (BlankUtil.isBlank(buildingId)) {
			return list;
		}
		BuildingDomain buildingDo = super.findById(buildingId);
		String home = buildingDo.getHome();
		if (BlankUtil.isBlank(home)) {
			return list;
		}
		Pattern pattern = Pattern.compile("\\A-?[1-9]\\d*"+SysInfo.SEPARATOR_COMMA+"-?[1-9]\\d*\\z");
		Matcher matcher = null;
		matcher = pattern.matcher(home);
		if (!matcher.matches()) {
			throw new BusinessException("house:building_illegal_home_exception",BusinessException.WARNING);
		}
		String[] homeArray = home.split(SysInfo.SEPARATOR_COMMA);

		int fromFloor = Integer.parseInt(homeArray[0]);

		int toFloor = Integer.parseInt(homeArray[1]);

		for (int i = fromFloor,j = 0; i <= toFloor; i++,j++) {
			list.add(j, i);
		}
		if (fromFloor < 0 && toFloor > 0) {
			list.remove(Integer.valueOf(0));
		}
		return list;
	}

	/**
	 *
	 * 功能描述: 根据楼栋单元id查询户型实体对象
	 *
	 * @author 付湘辉
	 * Created on:2008-7-1
	 *
	 * 修改原因：
	 * @param houseGrpId
	 * @return HouseGrp 返回结果
	 */
	public HouseGrp getHouseGrpById(Long houseGrpId){

		String queryStr = "FROM HouseGrp hg WHERE hg.id = ? ";

		Query query = super.createQuery(queryStr, new Object[]{houseGrpId});

		HouseGrp houseGrp = (HouseGrp)query.uniqueResult();

		return houseGrp;
	}

	/**
	 * 功能描述:验证住宅层是否已经有房间了
	 * @param
	 * @return
	 *
	 * Create author:xuhaidui
	 * Create on:2008-8-26
	 * Edit author:
	 * Edit on:
	 * Why:
	 */
	public List validationFloor(Long keyword, Integer homeFrom, Integer homeTo){

		String queryStr = "FROM FlatDomain flat WHERE flat.building.keyword = ? and (flat.floor< ? or flat.floor> ?)";

		Query query = super.createQuery(queryStr, new Object[]{keyword,homeFrom,homeTo});

		return query.list();
	}


	/**
	 * 功能描述:取出楼栋已经建了房间的最大和最小层数
	 * @param
	 * @return
	 *
	 * Create author:xuhaidui
	 * Create on:2008-8-26
	 * Edit author:
	 * Edit on:
	 * Why:
	 */
	public List<Integer> FloorMaxMin(Long keyword){
        List<Integer> list = new ArrayList();
		String queryStr = "SELECT max(flat.floor) FROM FlatDomain flat WHERE flat.building.id=? ";

		Query query = super.createQuery(queryStr, keyword);

		list.add((Integer)query.list().get(0));
		String minStr = "SELECT min(flat.floor) FROM FlatDomain flat WHERE flat.building.id=? ";
		query = super.createQuery(minStr, keyword);
		list.add((Integer)query.list().get(0));
		return list;
	}

	/**
	 *
	 * 功能描述: 根据楼盘id查询其所有楼栋信息
	 *
	 * @author 付湘辉
	 * Created on:2008-7-4
	 *
	 * 修改原因：
	 * @param areaId
	 * @return List<BuildingVO> 返回结果
	 */
	@BuildingQuery(alias = "bd", beginStr = " ", endStr = " AND ", insertAfterPoint = "WHERE", property4BuildingId = "keyword")
	public List<BuildingDomain> getBuildingListByAreaId(Long areaId){
		if (BlankUtil.isBlank(areaId)) {
			return null;
		}
		List<BuildingDomain> resultList = null;

		StringBuffer queryStr = new StringBuffer();
		queryStr.append("FROM BuildingDomain AS bd WHERE bd.area.id=? ");

		Query query = super.createQuery(queryStr.toString(), areaId);

		resultList = query.list();

		return resultList;
	}

	/**
	 * 功能描述: 根据收费管理区id查询其下的所有楼栋信息列表 <br>
	 * @param precinctId 收费管理区id
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-21  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public List<BuildingDomain> getBuildingListByPrecinctId(Long precinctId){
		List<BuildingDomain> resultList = null;

		if (BlankUtil.isBlank(precinctId)) {
			return new ArrayList<BuildingDomain>();
		}
		StringBuffer queryStr = new StringBuffer();
		queryStr.append("SELECT cp.buildings FROM ChargePrecinctDomain AS cp WHERE cp.id=? ");
		Query query = super.createQuery(queryStr.toString(), precinctId);

		resultList = query.list();

		return resultList;
	}

	/**
	 *
	 * 功能描述: 得到指定期数下楼栋编码最大值
	 *
	 * @author 付湘辉
	 * Created on:2008-7-9
	 *
	 * 修改原因：
	 * @param projectId
	 * @return Integer 返回结果
	 */
	public Integer getMaxSeqNoByProjectId(Long projectId){
		Integer maxSeqNo = null;

		String queryStr = "SELECT max(seqNo) FROM BuildingDomain bd where bd.project.keyword=? ";
		Object obj = super.createQuery(queryStr, projectId).uniqueResult();
		if (BlankUtil.isBlank(obj)) {
			return 0;
		}
		maxSeqNo =(Integer)obj;
		return maxSeqNo;
	}

	/**
	 * 功能描述: 根据建设期id和楼栋编码参数查询指定编码 <br>
	 * @param projectId
	 * @param seqNo
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-7-16  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public Integer getSeqNoBy(Long projectId, Integer seqNo){
		return this.getSeqNoBy(projectId, null, seqNo);
	}

	/**
	 * 功能描述: 根据建设期id和楼栋编码参数查询指定编码,要求id不是buildingId的楼栋<br>
	 * @param projectId
	 * @param buildingId
	 * @param seqNo
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-7-16  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public Integer getSeqNoBy(Long projectId,Long buildingId, Integer seqNo){
		Integer resultSeqNo = null;
		BuildingDomain buildingDo = this.getBuildingDomainBy(new Conditions(projectId,buildingId,seqNo));
		resultSeqNo = buildingDo==null?null:buildingDo.getSeqNo();
		return resultSeqNo;
	}

	/**
	 * 功能描述: 根据建设期id和楼栋编号参数查询指定楼栋实体 <br>
	 * @param projectId
	 * @param buildingSeqNo
	 * @return BuildingDomain
	 * Create author:胡煦 <br>
	 * Create on:2008-8-25  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BuildingDomain getBuildingByprojectId(Long projectId, Integer buildingSeqNo){
		return this.getBuildingDomainBy(new Conditions(projectId,buildingSeqNo));
	}
	/**
	 * 功能描述: 根据楼盘id和楼栋名称参数查询指定楼栋实体 <br>
	 * @param areaId
	 * @param buildingName
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-7-16  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BuildingDomain getBuildingDomainBy(Long areaId, String buildingName){
		return this.getBuildingDomainBy(areaId, null, buildingName);
	}
	/**
	 * 功能描述: 根据楼盘id和楼栋名称参数查询指定楼栋实体, 要求id不是buildingId的楼栋<br>
	 * @param areaId
	 * @param buildingId
	 * @param buildingName
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-7-16  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BuildingDomain getBuildingDomainBy(Long areaId,Long buildingId, String buildingName){
		return this.getBuildingDomainBy(new Conditions(areaId,buildingId,buildingName));
	}


	/**
	 * 功能描述: 获得一个楼栋实体对象，条件组合规则如下： <br>
	 * projectId 和 areaId 不能同时存在; projectId，areaId，buildingId 不能同时为空
	 * 1：只包含buildingId, 查询条件 =buildingId <br>
	 * 2：传buildingId，areaId 和buildingName, 查询条件是 <>buildingId and = areaId and = buildingName<br>
	 * 3：传buildingId，projectId 和seqNo, 查询条件是  <>buildingId and = projectId and = seqNo<br>
	 * 4：projectId 和seqNo, 查询条件是  = projectId and = seqNo<br>
	 * 5：areaId 和buildingName, 查询条件是  = areaId and = buildingName<br>
	 * @param conditions
	 * @return BuildingDomain
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-7-16  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	private BuildingDomain getBuildingDomainBy(Conditions conditions){

		Conditions.checkIsNull(conditions);

		Long areaId = conditions.getAreaId();
		Long projectId = conditions.getProjectId();
		Long buildingId = conditions.getBuildingId();
		String buildingName = conditions.getBuildingName();
		Integer seqNo = conditions.getSeqNo();

		final String buildKeywordOnlyStr = "bd.id=? ";
		String buildKeywordStr = "bd.id<>? AND ";
		String areaIdStr = "bd.area.id=? AND ";
		String projectIdStr = "bd.project.id=? AND ";
		String buildingNameStr = "bd.name=? AND ";
		String seqNoStr = "bd.seqNo=? AND ";
		String hql = "FROM BuildingDomain bd WHERE :buildKeywordStr :areaIdStr :buildProjectIdStr :buildingNameStr :seqNoStr ";

		List<Object> paramList = new ArrayList<Object>();
		int i = 0;

		if (conditions.checkIsOnlyBuildingId()) {
			areaIdStr="";
			projectIdStr="";
			buildingNameStr="";
			seqNoStr="";
			buildKeywordStr=buildKeywordOnlyStr;
			paramList.add(i++, buildingId);
		} else {

			if (!BlankUtil.isBlank(buildingId)) {
				paramList.add(i++, buildingId);
			}else
				buildKeywordStr="";

			if (!BlankUtil.isBlank(areaId)) {
				paramList.add(i++, areaId);
			}else
				areaIdStr="";

			if (!BlankUtil.isBlank(projectId)) {
				paramList.add(i++, projectId);
			}else
				projectIdStr="";

			if (!BlankUtil.isBlank(buildingName)) {
				paramList.add(i++, buildingName);
			}else
				buildingNameStr="";

			if (!BlankUtil.isBlank(seqNo)) {
				paramList.add(i++, seqNo);
			}else
				seqNoStr="";
		}

		hql = hql.replace(":buildKeywordStr "  , buildKeywordStr)
				 .replace(":areaIdStr "		   , areaIdStr)
				 .replace(":buildProjectIdStr ", projectIdStr)
				 .replace(":buildingNameStr "  , buildingNameStr)
				 .replace(":seqNoStr "		   , seqNoStr);

		if (hql.endsWith("AND ")) {
			hql = hql.substring(0, hql.lastIndexOf("AND "));
		}

		List list = this.createQuery(hql, paramList.toArray()).list();

		if(list.size() == 0) {
			return null;
		}

		return (BuildingDomain) list.get(0);
	}

	/**
	 * 功能描述: 根据楼栋id字符串得到楼栋实体列表,filterSign 为true 则表示buildingIds是要过滤的id
	 * 如果buildingIds为空，则返回楼栋表内所有的信息<br>
	 * @param buildingIds id字符串，如：1,2,3
	 * @param filterSign 过滤标志
	 * @return List<BuildingDomain>
	 *
	 * Create author:胡煦 <br>
	 * Create on:2008-7-18  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	private List<BuildingDomain> getBuildingsBy(String buildingIds,boolean filterSign) {
		List<BuildingDomain> list = new ArrayList<BuildingDomain>();
		if(BlankUtil.isBlank(buildingIds)){
			return findAll();
		}
		if (!Pattern.matches(SysrefcodeDO.REGEX_ID_JOIN_STRING, buildingIds)) {
			throw new BusinessException("common:id_join_string_format_exception",BusinessException.WARNING);
		}

		String queryStr = "FROM BuildingDomain bd WHERE bd.id :chooseStrategy (:idString) ";
		String chooseStrategy = "IN";
		if (filterSign) {
			chooseStrategy = "NOT IN";
		}
		queryStr=queryStr.replace(":chooseStrategy", chooseStrategy);
		queryStr=queryStr.replace(":idString", buildingIds);
		Query query=this.createQuery(queryStr);
		list = query.list();

		return list;
	}

	static class Conditions{
		private Long areaId;

		private Long projectId;

		private Long buildingId;

		private String buildingName;

		private Integer seqNo;

		/**
		 *
		 */
		Conditions() {
			super();
		}

		/**
		 * @param areaId
		 * @param buildingId
		 * @param buildingName
		 */
		Conditions(Long areaId, Long buildingId, String buildingName) {
			super();
			this.areaId = areaId;
			this.buildingId = buildingId;
			this.buildingName = buildingName;
		}

		/**
		 * @param projectId
		 * @param buildingId
		 * @param seqNo
		 */
		Conditions(Long projectId, Long buildingId, Integer seqNo) {
			super();
			this.projectId = projectId;
			this.buildingId = buildingId;
			this.seqNo = seqNo;
		}

		/**
		 * @param projectId
		 * @param seqNo
		 */
		Conditions(Long projectId, Integer seqNo) {
			super();
			this.projectId = projectId;
			this.seqNo = seqNo;
		}

		/**
		 * @param areaId
		 * @param buildingName
		 */
		Conditions(Long areaId, String buildingName) {
			super();
			this.areaId = areaId;
			this.buildingName = buildingName;
		}

		static void checkIsNull(Conditions conditions){
			if (BlankUtil.isBlank(conditions)
					|| (conditions.areaId == null
							&& conditions.projectId == null
							&& conditions.buildingId == null)
					|| (conditions.areaId != null
							&& conditions.projectId != null)) {
				throw new BusinessException("common:parameters_null_exception, ",BusinessException.WARNING);
			}
		}

		Boolean checkIsOnlyBuildingId(){
			return (buildingId != null
						&& areaId==null
						&& projectId==null
						&& BlankUtil.isBlank(buildingName)
						&& seqNo==null);
		}

		/**
		 * @return the areaId
		 */
		public Long getAreaId() {
			return areaId;
		}

		/**
		 * @param areaId the areaId to set
		 */
		public void setAreaId(Long areaId) {
			this.areaId = areaId;
		}

		/**
		 * @return the buildingId
		 */
		public Long getBuildingId() {
			return buildingId;
		}

		/**
		 * @param buildingId the buildingId to set
		 */
		public void setBuildingId(Long buildingId) {
			this.buildingId = buildingId;
		}

		/**
		 * @return the buildingName
		 */
		public String getBuildingName() {
			return buildingName;
		}

		/**
		 * @param buildingName the buildingName to set
		 */
		public void setBuildingName(String buildingName) {
			this.buildingName = buildingName;
		}

		/**
		 * @return the projectId
		 */
		public Long getProjectId() {
			return projectId;
		}

		/**
		 * @param projectId the projectId to set
		 */
		public void setProjectId(Long projectId) {
			this.projectId = projectId;
		}

		/**
		 * @return the seqNo
		 */
		public Integer getSeqNo() {
			return seqNo;
		}

		/**
		 * @param seqNo the seqNo to set
		 */
		public void setSeqNo(Integer seqNo) {
			this.seqNo = seqNo;
		}
	}
}
